package com.easylinkin.linkappapi.security.config;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easylinkin.bases.redis.util.RedisUtil;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import com.easylinkin.linkappapi.wxminiapp.WeChatUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LinkappMiniAppLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
	
	private String ivParameter = "iv";
	
	private String sessionKeyParameter = "sessionKey";
	
	private String encryptedDataParameter = "encryptedData";
	
	@Value("${wxminiapp.appid}")
	private String appid;
	
	@Resource
	LinkappUserService linkappUserService;
	@Autowired
	private RedisUtil redisUtil;
	private boolean postOnly = true;
	public LinkappMiniAppLoginAuthenticationFilter() {
        super(new AntPathRequestMatcher("/miniappLogin", "POST"));
    }

	@Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (postOnly && !"POST".equals(request.getMethod())) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		String username = null;
		String password = null;
		
		StringBuilder builder = new StringBuilder();
        try {
          BufferedReader bufferedReader = new BufferedReader(
                  new InputStreamReader(request.getInputStream(), "UTF-8"));
          String s;
          while ((s = bufferedReader.readLine()) != null) {
            builder.append(s);
          }
        } catch (IOException e) {
          log.error(e.getMessage(), e);
          throw new RuntimeException(e);
        }
        String text = builder.toString();
        if(StringUtils.isBlank(text)) {
          throw new IllegalArgumentException("提交内容不能为空");
        }
        JSONObject json = JSONObject.parseObject(text);
        
		String iv = json.getString("iv"); //obtainIv(request); 
		String sessionKey = json.getString("sessionKey"); //obtainSessionKey(request);
		String encryptedData = json.getString("encryptedData"); //obtainEncryptedData(request);	

		String decoded = null;
		JSONObject decodedObj = null;
		String decryptSessionKey = WeChatUtil.decryptSessionKey(sessionKey);
		if(null == decryptSessionKey) {
			throw new IllegalArgumentException("sessionKey错误");
		}
		try {
			decoded = WeChatUtil.decrypt(encryptedData, decryptSessionKey, iv);
			decodedObj = JSON.parseObject(decoded);
		} catch (Exception e) {
		    log.error("encryptedData: {}, decryptSessionKey: {}, iv: {}", encryptedData, decryptSessionKey, iv);
		    log.error(e.getMessage(), e);
			throw new IllegalArgumentException("解密失败" + e.getMessage(), e);
		}
		
		JSONObject watermark = decodedObj.getJSONObject("watermark");
		if (watermark == null || !StringUtils.equals(appid, watermark.getString("appid"))) {
			throw new IllegalArgumentException("appid校验失败");
		}
		
		String phone = decodedObj.getString("phoneNumber");
		LinkappUser query = new LinkappUser();
		query.setPhone(phone);
		List<LinkappUser> users = linkappUserService.selectUsers(query);
		if (ObjectUtils.isNotEmpty(users)) {
			redisUtil.set(sessionKey + "_miniapplogin", users.get(0), 3000);
			username = users.get(0).getUsername();
			password = users.get(0).getPassword();
		}
		if (username == null) {
			username = "error";
			LinkappUser user = new LinkappUser();
			user.setId(-1L);
			user.setUsername(username);
			redisUtil.set(sessionKey + "_miniapplogin", user, 3000);
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);

		return super.getAuthenticationManager().authenticate(authRequest);
	}

	@Override
  public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		super.setAuthenticationManager(authenticationManager);
	}

	protected String obtainIv(HttpServletRequest request) {
		return request.getParameter(ivParameter);
	}
	
	protected String obtainSessionKey(HttpServletRequest request) {
		return request.getParameter(sessionKeyParameter);
	}
	
	protected String obtainEncryptedData(HttpServletRequest request) {
		return request.getParameter(encryptedDataParameter);
	}

	protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
	}

	public void setPostOnly(boolean postOnly) {
		this.postOnly = postOnly;
	}


}
